package nl.tudelft.jpacman.level;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import nl.tudelft.jpacman.board.Board;
import nl.tudelft.jpacman.board.Direction;
import nl.tudelft.jpacman.board.Square;
import nl.tudelft.jpacman.board.Unit;
import nl.tudelft.jpacman.game.Game;
import nl.tudelft.jpacman.npc.Ghost;

@SuppressWarnings("PMD.TooManyMethods")
public class Level {
    public interface LevelObserver {
        void levelWon();
        void levelLost();
    }

    // 确保使用正确的接口类型
    private Set<LevelObserver> observers = new HashSet<>();
    private final Board board;
    private final Object moveLock = new Object();
    private final Object startStopLock = new Object();
    private final Map<Ghost, ScheduledExecutorService> npcs;
    private boolean inProgress;
    private List<Ghost> ghosts = new ArrayList<>();
    private List<Square> startPositions;
    private int startSquareIndex;
    private final List<Player> players;
    private final CollisionMap collisions;


    public Level(Board board, List<Ghost> ghosts, List<Square> startPositions,
                 CollisionMap collisionMap) {
        if (board == null) throw new IllegalArgumentException("Board cannot be null");
        if (collisionMap == null) throw new IllegalArgumentException("CollisionMap cannot be null");
        assert ghosts != null;
        assert startPositions != null;

        // 修复关键点：仅使用一次防御性拷贝
        this.ghosts = new ArrayList<>(ghosts); // 移除后续的 addAll 调用
        this.startPositions = new ArrayList<>(startPositions);
        this.board = board;
        this.inProgress = false;
        this.npcs = new HashMap<>();
        for (Ghost ghost : ghosts) {
            npcs.put(ghost, null);
        }
        this.startSquareIndex = 0;
        this.players = new ArrayList<>();
        this.collisions = collisionMap;
        this.observers = new HashSet<>();
    }
    public boolean isAnyPlayerAlive() {
        for (Player player : players) {
            if (player.isAlive()) {
                return true;
            }
        }
        return false;
        // 使用防御性拷贝
    }

    public int remainingPellets() {
        int pellets = 0;
        for (int x = 0; x < board.getWidth(); x++) {
            for (int y = 0; y < board.getHeight(); y++) {
                for (Unit unit : board.squareAt(x, y).getOccupants()) {
                    if (unit instanceof Pellet) {
                        pellets++;
                    }
                }
            }
        }
        return pellets;
    }

    public void start() {
        synchronized (startStopLock) {
            if (isInProgress()) return;
            startNPCs();
            inProgress = true;
            updateObservers();
        }
    }

    private void startNPCs() {
    }

    public void stop() {
        synchronized (startStopLock) {
            if (!isInProgress()) return;
            stopNPCs();
            inProgress = false;
        }
    }

    private void stopNPCs() {
    }

    public <LevelObserver> void addObserver(LevelObserver observer) {
        observers.add((Level.LevelObserver) observer);
    }


    public List<Square> getStartPositions() {
        return Collections.unmodifiableList(startPositions);
    }

    public List<Ghost> getGhosts() {
        return Collections.unmodifiableList(ghosts);
    }

    public void addGhost(Ghost ghost) {
        ghosts.add(ghost);
    }
    /**
     * Removes an observer if it was listed.
     *
     * @param observer
     *            The observer to be removed.
     */
    public void removeObserver(LevelObserver observer) {
        observers.remove(observer);
    }

    /**
     * Registers a player on this level, assigning him to a starting position. A
     * player can only be registered once, registering a player again will have
     * no effect.
     *
     * @param player
     *            The player to register.
     */
    public void registerPlayer(Player player) {
        assert player != null;
        assert !startPositions.isEmpty();

        if (players.contains(player)) {
            return;
        }
        players.add(player);
        Square square = startPositions.get(startSquareIndex);
        player.occupy(square);
        startSquareIndex = (startSquareIndex + 1) % startPositions.size();
    }

    public void move(Unit unit, Direction direction) {
        assert unit != null;
        assert direction != null;
        assert unit.hasSquare();

        if (!isInProgress()) {
            return;
        }

        synchronized (moveLock) {
            unit.setDirection(direction);
            Square location = unit.getSquare();
            Square destination = location.getSquareAt(direction);

            if (destination.isAccessibleTo(unit)) {
                List<Unit> occupants = destination.getOccupants();
                unit.occupy(destination);
                for (Unit occupant : occupants) {
                    collisions.collide(unit, occupant);
                }
            }
            updateObservers();
        }
    }

    private void updateObservers() {
    }

    private boolean isInProgress() {
        return false;
    }

    public Board getBoard() {
        return null;
    }
}
